#pragma once

#include "DX11Includes.h"
#include "EngineStuff.h"
#include "MeshUtils.h"
#include "AnimEvaluator.h"
#include "AnimationController.h"
#include <utility>

#define MAXBONES 100

class IMesh
{
public:
	IMesh(void);	
	~IMesh(void);		
	virtual HRESULT								Init(VertexData vertexData,int vertexCount,MeshTypeData type, UINT* indices, int indexCount,XMMATRIX &transformation,const char* modelName, const char* diffuseName ,D3D11_PRIMITIVE_TOPOLOGY topology,bool keepDataInRamMemory = false );		
	virtual HRESULT								Init(VertexData vertexData,int vertexCount,MeshTypeData type,XMMATRIX &transformation,const char* mmodelName ,const char* diffuseName = NULL ,D3D11_PRIMITIVE_TOPOLOGY topology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST,bool keepDataInRamMemory = false);
	virtual void								SetMeshOnDevice(void);
	virtual void								DrawMesh(void);	
	virtual void								Update(DWORD time);
	virtual ID3D11ShaderResourceView*			GetTexture(TextureTypes texMap);
	virtual void								SetTexture(const char* TextName , TextureTypes texMap);
	virtual void								SetTexture(ID3D11ShaderResourceView*  Text, TextureTypes texMap);	
	MeshTypeData								GetMeshType() {return meshTypeData;}
	XMMATRIX									*Transformation;

	///animation specific - botar numa subclasse (fix this "public" MESS !!!)
	AnimationController								*mAnimationController;
	int												mMyNode;			
	vector<std::pair<XMFLOAT4X4,int>>			 	BoneMatrix;	
	XMMATRIX										*AbsoluteBone;
	bool											Animated;	
	vector<SceneAnimNode*>							Nodes;


	IMesh* Clone()
	{
		IMesh* mesh = new IMesh();
		mesh->Animated = Animated;
		if(mesh->Animated)
		{
			mesh->mAnimationController  = mAnimationController->Clone();					
			mesh->BoneMatrix = BoneMatrix; 
		}

		mesh->mMyNode = mMyNode;			
		mesh->Nodes.resize(Nodes.size());
		for(int i = 0 ; i < Nodes.size();  i++)
		{
			mesh->Nodes[i] = Nodes[i]->Clone();
		}

			mesh->_indexCount = _indexCount;
			mesh->_vertexCount = _vertexCount;
			mesh->_vertexData = _vertexData;
			mesh->_indices = _indices;
			mesh->_topology = _topology;
			mesh->modelName = modelName;			
			mesh->g_pVertexBuffer = g_pVertexBuffer;
			mesh->g_pIndexBuffer = g_pIndexBuffer;
			mesh->g_pTextureRV = g_pTextureRV;
			mesh->stride = stride;
			mesh->meshTypeData = meshTypeData;				
			mesh->Transformation = Transformation ;
			return mesh;
	}	


	UINT* GetIndices()
	{
		return _indices;
	}

	void* GetVertexData()
	{
		switch(meshTypeData)
		{
			case MeshTypeData::PositionTextureNormalTangentBinormalAnimated:
			{
				return _vertexData.positionTextureNormalTangentBinormalAnimatedVertex;				
			}
			case MeshTypeData::PositionTextureNormalTangentBinormal:
			{
				return _vertexData.positionTextureNormalTangentBinormalVertex;
			}
			case MeshTypeData::PositionTextureNormal:
			{
				return _vertexData.positionTextureNormalVertex;
			}
			case MeshTypeData::PositionTexture:
			{
				///not yet implemented
				assert(false);
				break;
			}
		}
		return NULL;
	}

	void ClearRamInfo()
	{		
		if(_indices)		
		{
		delete [] _indices;		
		_indices = NULL;
		}

		switch(meshTypeData)
		{
			case MeshTypeData::PositionTextureNormalTangentBinormalAnimated:
			{
				if(_vertexData.positionTextureNormalTangentBinormalAnimatedVertex)				
					delete [] _vertexData.positionTextureNormalTangentBinormalAnimatedVertex;				
				break;
			}
			case MeshTypeData::PositionTextureNormalTangentBinormal:
			{
				if(_vertexData.positionTextureNormalTangentBinormalVertex)
					delete []  _vertexData.positionTextureNormalTangentBinormalVertex;
				break;
			}
			case MeshTypeData::PositionTextureNormal:
			{
				if(_vertexData.positionTextureNormalVertex)
					delete []  _vertexData.positionTextureNormalVertex;
				break;
			}
			case MeshTypeData::PositionTexture:
			{
				///not yet implemented
				assert(false);
				break;
			}
		}
	}

	int GetVertexCount() {return _vertexCount;}
	int GetIndexCount() {return _indexCount;}

	void SetVertexBuffer(ID3D11Buffer* vb, int vcount,UINT NewStride)
	{
		g_pVertexBuffer = vb;
		_vertexCount = vcount;
		stride = NewStride;
	}

	void SetIndexBuffer(ID3D11Buffer* vb, int icount)
	{
		g_pIndexBuffer= vb;
		_indexCount= icount;
	}

private:	
	int									_indexCount;
	int									_vertexCount;
	VertexData							_vertexData;
	UINT*								_indices;	
	D3D11_PRIMITIVE_TOPOLOGY			_topology;
	const char*							modelName;
	ID3D11Buffer*                       g_pVertexBuffer ;
	ID3D11Buffer*                       g_pIndexBuffer ;	
	ID3D11ShaderResourceView*           g_pTextureRV;
	UINT								stride;
	MeshTypeData						meshTypeData;

protected:
	void CalculateGlobalTransform( SceneAnimNode* pInternalNode);
	void UpdateSceneAnim();
	void UpdateTransforms( SceneAnimNode* pNode, XMMATRIX* pTransforms);
};